package com.xsmart.payment.services;

import com.xsmart.common.constant.ResultConstant;
import com.xsmart.common.entity.RequestBean;
import com.xsmart.common.entity.ResponseBean;
import com.xsmart.common.services.ApiCallService;
import com.xsmart.payment.dao.PayDao;
import com.xsmart.payment.domain.PayInfo;
import com.xsmart.payment.domain.PayLog;
import com.xsmart.payment.tools.CommonUtil;
import com.xsmart.payment.tools.HttpUtil;
import com.xsmart.payment.tools.RandomUtils;
import com.xsmart.payment.tools.TimeUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付
 *
 * @author guojd
 */
@Service
public class WxPaymentService {

    private static final Logger logger = LoggerFactory.getLogger(WxPaymentService.class);

    public static final String APP_ID = "APPID";

    //支付秘钥
    public static final String APP_KEY = "APP_KEY";

    //商户号
    public static final String MCH_ID = "MCH_ID";

    public static final String URL_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public static final String URL_ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery";

    public static final String URL_NOTIFY = "URL_NOTIFY";

    public static final String PAYMENT_TIME_EXPIRE = "PAYMENT_TIME_EXPIRE";

    public static final String SUCCESS_CODE = "SUCCESS";
    public static final String FAIL_CODE = "FAIL";

    public static final String SIGN_TYPE_DEFAULT = "MD5";


    /**
     * payment表pay_id值  微信支付
     */
    public static final String PAYMENT_ID_WEIXIN = "weixin";
    /**
     * pay_type 商品支付
     */
    public static final Integer PAY_TYPE_1 = 1;

    @Autowired
    private PayDao payDao;

    @Autowired
    private ApiCallService apiCallService;
    /**
     * 支付状态:0未付款;1付款中;2已付款;3支付失败
     */
    private static final String PAY_STATUS_0 = "0";
    private static final String PAY_STATUS_1 = "1";
    private static final String PAY_STATUS_2 = "2";
    private static final String PAY_STATUS_3 = "3";


    /**
     * 购物车结算 获取数据
     *
     * @param requestBean 请求对象
     *                    order_id:订单id
     *                    order_sn:订单编号
     *                    uid:用户id
     * @return 成功失败
     */
    public ResponseBean wxpay(RequestBean requestBean) {
        ResponseBean responseBean = requestBean.getResponseBean();
        Integer recId = requestBean.getRequestParamInteger("rec_id");
        if (recId == null) {
            responseBean.setResult(ResultConstant.ERROR);
            responseBean.setMessage("请求错误");
            return responseBean;
        }

        responseBean.setResult(ResultConstant.SUCCESS);
        return responseBean;
    }

    /**
     * 微信预付
     *
     * @param openid
     * @param clientIp
     * @return
     * @throws Exception
     */
    public PayInfo wxprepay(String openid, String clientIp, Integer totalFee) throws Exception {
        PayInfo payInfo = null;
        try {
            String randomNonceStr = RandomUtils.generateMixString(32);
            payInfo = unifiedOrder(openid, clientIp, randomNonceStr, totalFee);

            if (payInfo == null || StringUtils.isBlank(payInfo.getPrepayId())) {
                throw new Exception(ResultConstant.ERROR_PREPAYID_NULL);
            }

        } catch (Exception e) {
            logger.error(e.getMessage());
            throw e;
        } finally {
            return payInfo;
        }
    }

    /**
     * 调用统一下单接口
     *
     * @param openId
     */
    private PayInfo unifiedOrder(String openId, String clientIP, String randomNonceStr, Integer totalFee) throws Exception {

        try {
            PayInfo payInfo = createPayInfo(openId, clientIP, randomNonceStr, totalFee);
            String md5 = getPrePaySign(payInfo);
            payInfo.setSign(md5);

            logger.info("md5 value: " + md5);

            String xml = CommonUtil.payInfoToXML(payInfo);
            xml = xml.replace("__", "_").replace("<![CDATA[1]]>", "1");
            logger.info(xml);

            StringBuffer buffer = HttpUtil.httpsRequest(URL_UNIFIED_ORDER, "POST", xml);
            logger.info("unifiedOrder request return body: \n" + buffer.toString());
            Map<String, String> result = CommonUtil.parseXml(buffer.toString());


            String return_code = result.get("return_code");
            if (StringUtils.isNotBlank(return_code) && return_code.equals(SUCCESS_CODE)) {

                //业务结果
                String return_msg = result.get("result_code");
                if (StringUtils.isNotBlank(return_msg) && !return_msg.equals(SUCCESS_CODE)) {
                    //错误代码描述
                    String errCodeDes = result.get("err_code_des");
                    logger.info("统一下单返回错误信息：" + errCodeDes);
                    throw new Exception(errCodeDes);
                }
                String prepay_Id = result.get("prepay_id");
                payInfo.setPrepayId(prepay_Id);
                return payInfo;

            } else {
                String returnMsg = result.get("return_msg");
                throw new Exception(returnMsg);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr, Integer totalFee) {

        Date date = new Date();
        String timeStart = TimeUtils.getFormatTime(date, TimeUtils.DATE_FORMAT_2);
        int paymentTimeExpire = Integer.parseInt(getSysParamVal(PAYMENT_TIME_EXPIRE));
        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addHour(date, paymentTimeExpire), TimeUtils.DATE_FORMAT_2);

        String randomOrderId = CommonUtil.getRandomOrderId();

        PayInfo payInfo = new PayInfo();
        payInfo.setAppid(getSysParamVal(APP_ID));
        payInfo.setMch_id(getSysParamVal(MCH_ID));
        payInfo.setDevice_info("WEB");
        payInfo.setNonce_str(randomNonceStr);
        //默认即为MD5
        payInfo.setSign_type(SIGN_TYPE_DEFAULT);
        payInfo.setBody("大肚商城支付");
        payInfo.setAttach("大肚商城支付");
        payInfo.setOut_trade_no(randomOrderId);
        //订单总金额，单位为分
        payInfo.setTotal_fee(totalFee);
        payInfo.setSpbill_create_ip(clientIP);
        payInfo.setTime_start(timeStart);
        payInfo.setTime_expire(timeExpire);
        // URL_NOTIFY
        payInfo.setNotify_url(getSysParamVal(URL_NOTIFY));
        payInfo.setTrade_type("JSAPI");
        payInfo.setLimit_pay("no_credit");
        payInfo.setOpenid(openId);

        return payInfo;
    }

    private String getPrePaySign(PayInfo payInfo) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + payInfo.getAppid())
                .append("&attach=" + payInfo.getAttach())
                .append("&body=" + payInfo.getBody())
                .append("&device_info=" + payInfo.getDevice_info())
                .append("&limit_pay=" + payInfo.getLimit_pay())
                .append("&mch_id=" + payInfo.getMch_id())
                .append("&nonce_str=" + payInfo.getNonce_str())
                .append("&notify_url=" + payInfo.getNotify_url())
                .append("&openid=" + payInfo.getOpenid())
                .append("&out_trade_no=" + payInfo.getOut_trade_no())
                .append("&sign_type=" + payInfo.getSign_type())
                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
                .append("&time_expire=" + payInfo.getTime_expire())
                .append("&time_start=" + payInfo.getTime_start())
                .append("&total_fee=" + payInfo.getTotal_fee())
                .append("&trade_type=" + payInfo.getTrade_type())
                .append("&key=" + getSysParamVal(APP_KEY));

        logger.info("排序后的拼接参数：" + sb.toString());

        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

    /**
     * 获取微信支付请求参数
     *
     * @param requestBean
     * @return
     */
    @Transactional
    public ResponseBean getPayParam(RequestBean requestBean, String clientIp) {
        ResponseBean responseBean = requestBean.getResponseBean();
        String openid = requestBean.getRequestParamString("openid");
        String orderId = requestBean.getRequestParamString("orderId");
        String orderAmount = requestBean.getRequestParamString("orderAmount");

        Integer totalFee;
        if (StringUtils.isBlank(openid)) {
            responseBean.setResult(ResultConstant.ERROR);
            responseBean.setMessage(ResultConstant.ERROR_OPENID_NULL);
            return responseBean;
        }

        if (StringUtils.isBlank(orderId)) {
            responseBean.setResult(ResultConstant.ERROR);
            responseBean.setMessage(ResultConstant.ERROR_ORDERID_NULL);
            return responseBean;
        }
        if (StringUtils.isBlank(orderAmount)) {
            responseBean.setResult(ResultConstant.ERROR);
            responseBean.setMessage(ResultConstant.ERROR_ORDERAMOUNT_NULL);
            return responseBean;
        } else {
            try {
                float totalFeeFloat = Float.parseFloat(orderAmount) * 100;
                totalFee = new Float(totalFeeFloat).intValue();
            } catch (Exception e) {
                responseBean.setResult(ResultConstant.ERROR);
                responseBean.setMessage("订单金融错误");
                return responseBean;
            }
        }

        Map<String, Object> paramMap = new HashMap();
        paramMap.put("appId", getSysParamVal(APP_ID));
        paramMap.put("timeStamp", System.currentTimeMillis() + "");
        String randomNonceStr = RandomUtils.generateMixString(32);
        paramMap.put("nonceStr", randomNonceStr);
        try {
            PayInfo payInfo = wxprepay(openid, clientIp, totalFee);
            String prepayId = payInfo.getPrepayId();

            //插入pay_log表
            PayLog payLog = new PayLog();
            Map<String,Object> paymentMap = payDao.findPaymentByPayCode(PAYMENT_ID_WEIXIN);
            payLog.setPayId(MapUtils.getInteger(paymentMap,"pay_id"));
            payLog.setPayTypeId(PAY_TYPE_1);
            payLog.setIsPaid(0);
            payLog.setOrderAmount(Float.valueOf(orderAmount));
            payLog.setOrderId(Integer.valueOf(orderId));
            payLog.setPayCode(payInfo.getOut_trade_no());
            //付款中
            payLog.setPayStatus("1");
            payLog.setPayTime(payInfo.getTime_start());
            payLog.setPayExpireTime(payInfo.getTime_expire());
            payDao.insertPayLog(payLog);

            //插入pay_log_curr表
            payDao.deletePayLogCurr(payLog.getOrderId());
            Map payLogCurrMap = new HashMap<String, String>(2);
            payLogCurrMap.put("logId", payLog.getLogId());
            payLogCurrMap.put("orderId", payLog.getOrderId());
            payDao.insertPayLogCurr(payLogCurrMap);
            //插入pay_log_weixin
            payLogCurrMap.put("prepayId", prepayId);
            payDao.insertPayLogWeixin(payLogCurrMap);

            if (StringUtils.isBlank(prepayId)) {
                throw new Exception(ResultConstant.ERROR_PREPAYID_NULL);
            }
            paramMap.put("package", "prepay_id=" + prepayId);
            //固定
            paramMap.put("signType", SIGN_TYPE_DEFAULT);
            String paySign = getPaymentSign(paramMap);
            paramMap.put("paySign", paySign);
            responseBean.setResult(ResultConstant.SUCCESS);
            responseBean.setResultData(paramMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            responseBean.setResult(ResultConstant.ERROR);
            responseBean.setMessage(e.getMessage().substring(0, 50));
        } finally {
            return responseBean;
        }
    }

    private String getPaymentSign(Map<String, Object> paramMap) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("appId=" + paramMap.get("appId"))
                .append("&nonceStr=" + paramMap.get("nonceStr"))
                .append("&package=" + paramMap.get("package"))
                .append("&signType=" + paramMap.get("signType"))
                .append("&timeStamp=" + paramMap.get("timeStamp"))
                .append("&key=" + getSysParamVal(APP_KEY));

        logger.info("排序后的拼接参数：" + sb.toString());
        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

    /**
     * 支付结果通知
     *
     * @param requestXml
     * @return
     * @throws Exception
     */
    public String notifyPaymentResult(RequestBean requestBean, String requestXml) {
        logger.info("支付结果通知报文：" + requestXml);
        ResponseBean responseBean = requestBean.getResponseBean();
        String reponseCode = SUCCESS_CODE;
        String reponseMsg = "OK";
        try {
            Map<String, String> result = CommonUtil.parseXml(requestXml);
            String returnCode = MapUtils.getString(result, "return_code");
            if (FAIL_CODE.equals(returnCode)) {
                //需要确定通信标识为失败时的处理方式  待解决
                reponseCode = FAIL_CODE;
                reponseMsg = "通信失败";
            } else if (SUCCESS_CODE.equals(returnCode)) {
                String payCode = MapUtils.getString(result, "out_trade_no");
                Map payLogMap = payDao.findByPayCode(payCode);
                //先校验支付记录是否存在,如果不存在直接返回成功
                if (payLogMap != null) {
                    //支付状态:0未付款;1付款中;2已付款;3支付失败
                    String payStatus = MapUtils.getString(payLogMap, "pay_status");
                    //除了已付款  其他重新走逻辑
                    if (!PAY_STATUS_2.equals(payStatus)) {
                        //业务结果
                        String resultCode = MapUtils.getString(result, "result_code");
                        Map paramMap = new HashMap<String, Object>(16);

                        String requestAmount = MapUtils.getString(result, "total_fee");
                        paramMap.put("payCode", payCode);
                        String endTime = MapUtils.getString(result, "time_end");
                        paramMap.put("payEndTime", TimeUtils.getFormatTime(endTime, TimeUtils.DATE_FORMAT_2, TimeUtils.DATE_FORMAT_1));
                        paramMap.put("transactionId", MapUtils.getString(result, "transaction_id"));
                        String statusTime = TimeUtils.getFormatTime(new Date(), TimeUtils.DATE_FORMAT_1);

                        paramMap.put("statusTime", statusTime);
                        //做检验 1、签名验证
                        String signIn = MapUtils.getString(result, "sign");
                        String signAssemble = getPayResultNoticeSign(result);
                        if (signIn.equals(signAssemble)) {
                            // 2、校验返回的订单金额是否与商户侧的订单金额一致

                            paramMap.put("logId", MapUtils.getString(payLogMap, "log_id"));
                            //先校验支付记录是否存在,如果不存在直接返回成功
                            //单位分
                            String orderAmount = MapUtils.getString(payLogMap, "order_amount");
                            float totalFeeFloat = Float.parseFloat(orderAmount) * 100;
                            int totalFee = new Float(totalFeeFloat).intValue();
                            if (requestAmount.equals(totalFee + "")) {

                                String payStatusDone = "";
                                //判断逻辑是否失败
                                if (FAIL_CODE.equals(resultCode)) {
                                    paramMap.put("errCode", MapUtils.getString(result, "err_code"));
                                    paramMap.put("errCodeDes", MapUtils.getString(result, "err_code_des"));
                                    payStatusDone = PAY_STATUS_3;
                                } else if (SUCCESS_CODE.equals(resultCode)) {
                                    payStatusDone = PAY_STATUS_2;
                                    //调用定单归档接口 传入 orderId 和 支付金额 orderAmount
                                    Map<String,Object> payLogCurrMap = payDao.findPayLogCurrByLogId(MapUtils.getString(payLogMap, "log_id"));
                                    String orderId = MapUtils.getString(payLogCurrMap,"order_id");
                                    Map<String, Object> modOrderMap = new HashMap<>();
                                    modOrderMap.put("id", orderId);
                                    modOrderMap.put("orderAmount", orderAmount);
                                    modOrderMap.put("type", "confirmPay");
                                    requestBean.setPrivates(modOrderMap);
                                    apiCallService.call("v1", "WxOrderListService", "modOrderStatus", requestBean, null);
                                }
                                paramMap.put("responseXml", requestXml);
                                //更新pay_log_weixin表
                                payDao.updatePayLogWeixin(paramMap);
                                //更新pay_log
                                paramMap.put("payStatus", payStatusDone);
                                payDao.updatePayLog_PayStatus(paramMap);

                                reponseCode = SUCCESS_CODE;
                            } else {
                                reponseCode = FAIL_CODE;
                                reponseMsg = "订单金额不一致";
                            }
                        } else {
                            reponseCode = FAIL_CODE;
                            reponseMsg = "签名检验失败";
                        }
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            reponseCode = FAIL_CODE;
            reponseMsg = e.getMessage().substring(0, 50);
        } finally {
            String returnInfo = "<xml>\n" +
                    "<return_code><![CDATA[" + reponseCode + "]]></return_code>\n" +
                    "  <return_msg><![CDATA[" + reponseMsg + "]]></return_msg>\n" +
                    "</xml>";
            logger.info(returnInfo);
            return returnInfo;
        }
    }

    private String getElementText(Element ele, String paramCode) throws Exception {
        String eleVal = ele.element(paramCode).getText();
        return eleVal.replaceAll("<!\\[CDATA\\[", "").replaceAll("]]>", "");
    }

    /**
     * 查询订单 查询支付结果
     * 直接获取openid和logId
     *
     * @param requestBean
     * @return
     */
    public ResponseBean orderQuery(RequestBean requestBean) {
        ResponseBean responseBean = requestBean.getResponseBean();

        String payCode;
        int reponseCode = ResultConstant.SUCCESS;
        String reponseMsg = "OK";
        try {
            //通过id查询支付记录
            String orderId = requestBean.getRequestParamString("orderId");
            Map payLogMap = payDao.findPayLogByOrderId(orderId);
            if (payLogMap != null) {
                String payStatus = MapUtils.getString(payLogMap, "pay_status");
                //支付状态:0未付款;1付款中;2已付款;3支付失败  不处理已付款
                if (!PAY_STATUS_2.equals(payStatus)) {
                    payCode = MapUtils.getString(payLogMap, "pay_code");
                    String randomNonceStr = RandomUtils.generateMixString(32);
                    String sign = getOrderquerySign(randomNonceStr, payCode);
                    String orderQueryStr = assembleRequestXml(randomNonceStr, payCode, sign);
                    //调用查询订单接口
                    StringBuffer buffer = HttpUtil.httpsRequest(URL_ORDERQUERY, "POST", orderQueryStr);
                    logger.info("orderQuery request return body: \n" + buffer.toString());
                    //把报文转成Map类型
                    Map<String, String> resultMap = CommonUtil.parseXml(buffer.toString());
                    String returnCode = MapUtils.getString(resultMap, "return_code");

                    if (SUCCESS_CODE.equals(returnCode)) {
                        String resultCode = MapUtils.getString(resultMap, "result_code");
                        if (SUCCESS_CODE.equals(resultCode)) {
                            //业务结果
                            String tradeState = getMapValue(resultMap, "trade_state");
                            Map paramMap = new HashMap<String, Object>(16);
                            payCode = getMapValue(resultMap, "out_trade_no");
                            String requestAmount = getMapValue(resultMap, "total_fee");
                            paramMap.put("payCode", payCode);
                            paramMap.put("payEndTime", getMapValue(resultMap, "time_end"));
                            paramMap.put("transactionId", getMapValue(resultMap, "transaction_id"));
                            String statusTime = TimeUtils.getFormatTime(new Date(), TimeUtils.DATE_FORMAT_1);
                            paramMap.put("statusTime", statusTime);
                            //做检验 1、签名验证 待解决
                            String signIn = MapUtils.getString(resultMap, "sign");
                            String signAssemble = getPayResultNoticeSign(resultMap);
                            if (signIn.equals(signAssemble)) {
                                // 2、校验返回的订单金额是否与商户侧的订单金额一致
                                paramMap.put("logId", MapUtils.getString(payLogMap, "log_id"));
                                //单位分
                                String orderAmount = MapUtils.getString(payLogMap, "order_amount");
                                float totalFeeFloat = Float.parseFloat(orderAmount) * 100;
                                int totalFee = new Float(totalFeeFloat).intValue();
                                if (requestAmount.equals(totalFee + "")) {
                                    //支付状态:0未付款;1付款中;2已付款;3支付失败
                                    String payStatusDone;
                                    //判断逻辑是否失败
                                    if (SUCCESS_CODE.equals(tradeState)) {
                                        payStatusDone = PAY_STATUS_2;
                                    } else {
                                        paramMap.put("errCode", tradeState);
                                        paramMap.put("errCodeDes", getMapValue(resultMap, "trade_state_desc"));
                                        payStatusDone = PAY_STATUS_3;
                                    }
                                    paramMap.put("responseXml", buffer.toString());
                                    //更新pay_log_weixin表
                                    payDao.updatePayLogWeixin(paramMap);
                                    //更新pay_log
                                    paramMap.put("payStatus", payStatusDone);
                                    payDao.updatePayLog_PayStatus(paramMap);
                                } else {
                                    reponseCode = ResultConstant.ERROR;
                                    reponseMsg = "订单金额不一致";
                                }
                            } else {
                                reponseCode = ResultConstant.ERROR;
                                reponseMsg = "签名错误";
                            }
                        } else {
                            reponseCode = ResultConstant.ERROR;
                            reponseMsg = "交易失败";
                        }
                    } else {
                        reponseCode = ResultConstant.ERROR;
                        reponseMsg = "交易失败";
                    }
                }
            } else {
                reponseCode = ResultConstant.ERROR;
                reponseMsg = "支付记录未入库";
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            reponseCode = ResultConstant.ERROR;
            reponseMsg = e.getMessage().substring(0, 50);
        }finally{
            responseBean.setResult(reponseCode);
            responseBean.setMessage(reponseMsg);
            return responseBean;

        }

    }

    private String getOrderquerySign(String nonceStr, String payCode) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + getSysParamVal(APP_ID))
                .append("&mch_id=" + getSysParamVal(MCH_ID))
                .append("&nonce_str=" + nonceStr)
                .append("&out_trade_no=" + payCode)
                .append("&key=" + getSysParamVal(APP_KEY));

        logger.info("排序后的拼接参数：" + sb.toString());

        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

    private String assembleRequestXml(String nonceStr, String payCode, String sign) {
        StringBuffer orderQueryXml = new StringBuffer();
        orderQueryXml.append("<xml>");
        orderQueryXml.append("<appid>" + getSysParamVal(APP_ID) + "</appid>");
        orderQueryXml.append("<mch_id>" + getSysParamVal(MCH_ID) + "</mch_id>");
        orderQueryXml.append("<nonce_str>" + nonceStr + "</nonce_str>");
        orderQueryXml.append("<out_trade_no>" + payCode + "</out_trade_no>");
        orderQueryXml.append("<sign>" + sign + "</sign></xml>");
        return orderQueryXml.toString();
    }

    private String getMapValue(Map<String, String> map, String paramCode) throws Exception {
        String paramVal = MapUtils.getString(map, paramCode);
        return paramVal.replaceAll("<!\\[CDATA\\[", "").replaceAll("]]>", "");
    }


    private String getPayResultNoticeSign(Map<String, String> result) throws Exception {
        StringBuffer sb = new StringBuffer();
        String deviceInfo = MapUtils.getString(result, "device_info") == null ? "" : MapUtils.getString(result, "device_info");
        String signType = MapUtils.getString(result, "sign_type") == null ? "" : MapUtils.getString(result, "sign_type");
        String errCode = MapUtils.getString(result, "err_code") == null ? "" : MapUtils.getString(result, "err_code");
        String errCodeDes = MapUtils.getString(result, "err_code_des") == null ? "" : MapUtils.getString(result, "err_code_des");
        String isSubscribe = MapUtils.getString(result, "is_subscribe") == null ? "" : MapUtils.getString(result, "is_subscribe");
        String settlementTotalFee = MapUtils.getString(result, "settlement_total_fee") == null ? "" : MapUtils.getString(result, "settlement_total_fee");
        String feeType = MapUtils.getString(result, "fee_type") == null ? "" : MapUtils.getString(result, "fee_type");
        String cashFeeType = MapUtils.getString(result, "cash_fee_type") == null ? "" : MapUtils.getString(result, "cash_fee_type");
        String couponFee = MapUtils.getString(result, "coupon_fee") == null ? "" : MapUtils.getString(result, "coupon_fee");
        String couponCount = MapUtils.getString(result, "coupon_count") == null ? "" : MapUtils.getString(result, "coupon_count");

        String couponType_$n = MapUtils.getString(result, "coupon_type_$n") == null ? "" : MapUtils.getString(result, "coupon_type_$n");
        String couponId_$n = MapUtils.getString(result, "coupon_id_$n") == null ? "" : MapUtils.getString(result, "coupon_id_$n");
        String couponFee_$n = MapUtils.getString(result, "coupon_fee_$n") == null ? "" : MapUtils.getString(result, "coupon_fee_$n");
        String attach = MapUtils.getString(result, "attach") == null ? "" : MapUtils.getString(result, "attach");
        String returnMsg = MapUtils.getString(result, "return_msg") == null ? "" : MapUtils.getString(result, "return_msg");
        String tradeState = MapUtils.getString(result, "trade_state") == null ? "" : MapUtils.getString(result, "trade_state");
        String tradeStateDesc = MapUtils.getString(result, "trade_state_desc") == null ? "" : MapUtils.getString(result, "trade_state_desc");


        sb.append("appid=" + MapUtils.getString(result, "appid"))
                .append(attach.equals("") ? "" : "&attach=" + attach)
                .append("&bank_type=" + MapUtils.getString(result, "bank_type"))
                .append("&cash_fee=" + MapUtils.getString(result, "cash_fee"))

                .append(cashFeeType.equals("") ? "" : "&cash_fee_type=" + cashFeeType)
                .append(couponCount.equals("") ? "" : "&coupon_count=" + couponCount)
                .append(couponFee.equals("") ? "" : "&coupon_fee=" + couponFee)

                .append(couponFee_$n.equals("") ? "" : "&coupon_fee_$n=" + couponFee_$n)
                .append(couponId_$n.equals("") ? "" : "&coupon_id_$n=" + couponId_$n)
                .append(couponType_$n.equals("") ? "" : "&coupon_type_$n=" + couponType_$n)

                .append(deviceInfo.equals("") ? "" : "&device_info=" + deviceInfo)

                .append(errCode.equals("") ? "" : "&err_code=" + errCode)
                .append(errCodeDes.equals("") ? "" : "&err_code_des=" + errCodeDes)

                .append(feeType.equals("") ? "" : "&fee_type=" + feeType)
                .append(isSubscribe.equals("") ? "" : "&is_subscribe=" + isSubscribe)

                .append("&mch_id=" + MapUtils.getString(result, "mch_id"))
                .append("&nonce_str=" + MapUtils.getString(result, "nonce_str"))
                .append("&openid=" + MapUtils.getString(result, "openid"))

                .append("&out_trade_no=" + MapUtils.getString(result, "out_trade_no"))
                .append("&result_code=" + MapUtils.getString(result, "result_code"))
                .append("&return_code=" + MapUtils.getString(result, "return_code"))
                .append(returnMsg.equals("") ? "" : "&return_msg=" + returnMsg)
                .append(settlementTotalFee.equals("") ? "" : "&settlement_total_fee=" + settlementTotalFee)
                .append(signType.equals("") ? "" : "&sign_type=" + signType)

                .append("&time_end=" + MapUtils.getString(result, "time_end"))
                .append("&total_fee=" + MapUtils.getString(result, "total_fee"))

                .append(tradeState.equals("") ? "" : "&trade_state=" + tradeState)
                .append(tradeStateDesc.equals("") ? "" : "&trade_state_desc=" + tradeStateDesc)
                .append("&trade_type=" + MapUtils.getString(result, "trade_type"))
                .append("&transaction_id=" + MapUtils.getString(result, "transaction_id"))
                .append("&key=" + getSysParamVal(APP_KEY));

        logger.info("排序后的拼接参数：" + sb.toString());

        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

    private String getSysParamVal(String paramCode){
        Map<String,Object> paramMap = payDao.findByParamCode(paramCode);
        return MapUtils.getString(paramMap,"param_value");
    }
}
